<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * 消息业务
 * 
 * @desc	消息业务模型，函数库：处理前后台消息相关的业务。
 * @version	1.0.0 
 * @author	Jason
 * @date	2017年7月21日 下午1:39:08
 * 
 * @desc	终于解决了两个问题：阻塞、超载！
 * @version	1.0.1 
 * @author	Jason
 * @date	2017年7月28日 下午2:15:22
 */
class Lib_message extends Lib_database
{
	/** @var Mod_message */
	private $mod_message = null;
	
	use libraries\common\DatabaseCURD;
	
	use libraries\common\ConditionParser;
	
	public function __construct()
	{
		parent::__construct();
		
		$this->CI->config->load('enumeration');
		
		$this->CI->load->model('mod_message');
		$this->mod_message =& $this->CI->mod_message;
		
		$this->set_render_config();
	}
	
	private function set_render_config()
	{
		$this->CI->load->model('mod_member');
		$foreign_keys = [
				'master' => [
						['template_id', ['name', 'code'], $this->mod_message, 'template', 'id'],
						['source_id', ['name', 'email', 'mobile'], $this->CI->mod_member, 'master', 'id'],
						['source_id', ['nickname'], $this->CI->mod_member, 'info', 'id'],
						['target_id', ['name', 'email', 'mobile'], $this->CI->mod_member, 'master', 'id'],
						['target_id', ['nickname'], $this->CI->mod_member, 'info', 'id'],
				],
				'template' => [
				],
				'container' => [
						['message_id', ['content', 'send_time', 'extra'], $this->mod_message, 'master', 'id'],
						['template_id', ['name', 'code', 'model', 'oper', 'value', 'other', 'medium', 'channel', 'extra'], $this->mod_message, 'template', 'id'],
				],
		];
		$time_fields = [
				'master' => [
						['create_time', 'Y-m-d H:i:s'],
						['send_time', 'Y-m-d H:i:s'],
				],
				'template' => [
				],
				'container' => [
						['receive_time', 'Y-m-d H:i:s'],
				],
		];
		$encode_fields = [
				'master' => [
						// not friendly to formatMessageContent!!
// 						['content', 'serialize'],	// 消息内容，一般存的是消息模板变量所需内容的JSON格式或其它串行化格式
// 						['extra', 'serialize'],		// 消息额外字段信息
				],
				'template' => [
// 						['extra', 'serialize'],		// 额外参数
				],
				'container' => [
				],
		];
		$this->foreign_keys = $foreign_keys;
		$this->time_fields = $time_fields;
		$this->encode_fields = $encode_fields;
	}
	
	
	public function get_message_for_detail($id)
	{
		$item = $this->mod_message->select_instance_by_id($id);
		$item = $this->render_list($item, 'master', true, [
				[$this, 'parse_message_item'],
		]);
		return $item;
	}
	
	public function get_messages_for_list($conditions, $page = 1, $number = 12)
	{
		$data = $this->mod_message->get_list($conditions, $page, $number);
		$data['data'] = $this->render_list($data['data'], 'master', false, [
				[$this, 'parse_message_item'],
		]);
		return $data;
	}
	
	public function get_template_for_detail($id)
	{
		$item = $this->mod_message->select_instance_by_id($id, 'template');
		$item = $this->render_list($item, 'template', true, [
				[$this, 'parse_template_item'],
		]);
		return $item;
	}
	
	public function get_templates_for_list($conditions, $page = 1, $number = 12)
	{
		$data = $this->mod_message->get_list($conditions, $page, $number, 'template');
		$data['data'] = $this->render_list($data['data'], 'template', false, [
				[$this, 'parse_template_item'],
		]);
		return $data;
	}
	
	public function get_container_for_detail($id)
	{
		$item = $this->mod_message->select_instance_by_id($id, 'container');
		$item = $this->render_list($item, 'container', true, [
				[$this, 'parse_container_item'],
		]);
		return $item;
	}
	
	public function get_containers_for_list($conditions, $page = 1, $number = 12)
	{
		$data = $this->mod_message->get_list($conditions, $page, $number, 'container');
		$data['data'] = $this->render_list($data['data'], 'container', false, [
				[$this, 'parse_container_item'],
		]);
		return $data;
	}
	
	/**
	 * 收取新消息，指定媒介
	 * 
	 * @desc    收取指定媒介的新消息
	 * @author  Jason
	 * @date    2017年7月27日 下午3:03:22
	 * 
	 * @param   number $target_id
	 * @param   string $template_medium
	 * 
	 * @return  void
	 */
	public function receive_new_messages($target_id, $template_medium = 'WEB')
	{
		/*
		// 取 last_id 方法一：取出符合条件的全部历史数据，按 `id` 逆序排，然后根据最大的 `id` 取 `target_id` 做为 last_id。
		$conditions = [
				['select', 'message_id'],
				['where', "`target_id`='{$target_id}'"],
				['where', "`template_medium`='{$template_medium}'"],
				['order_by', 'id DESC'],
				['limit', 1],
		];
		$last_id = $this->mod_message->select_instance_by_conditions($conditions, 'container');
		$last_id = $last_id ? $last_id['message_id'] : 0;
		//printf("SQL: %s <br>\n\t -> Result: %d<br>\n", $this->mod_message->db->last_query(), $last_id);
		*/
		
		// 取 last_id 方法二：直接取出符合条件的最大的 `message_id` 做为 last_id。
		$last_id = $this->mod_message->db
										->select_max('message_id', 'last_id')
										->from('message_container')
										->where("`target_id`='{$target_id}'")
										->where("`template_medium`='$template_medium'")
										->get()->row_object()->last_id;
		$last_id = $last_id ? : 0;
		//printf("SQL: %s <br>\n\t -> %d<br>\n", $this->mod_message->db->last_query(), $last_id);
		
		$conditions = [
				// MARK 消息发送媒介冗余字段：双表系统是可以不冗余该字段的。但是三表比较麻烦：IN局限，联表慢，故冗余。
				['select', 'source_id, template_id, template_medium, id'],
				['where', "id > $last_id"],
				// MARK 消息发送媒介冗余字段：双表系统是可以不冗余该字段的。但是三表比较麻烦：IN局限，联表慢，故冗余。
				['where', "`template_medium`='{$template_medium}'"],
				['where_in', ['target_id', [$target_id, '0']]],
		];
		$messages = $this->mod_message->select_instances_by_conditions($conditions, 'master');
		foreach ($messages as $message) {
			$message['target_id'] = $target_id;
			$message['message_id'] = $message['id'];
			$message['receive_time'] = time();
			$this->mod_message->create_instance($message, 'container');
		}
	}
	
	public function parse_message_item($item)
	{
		$item['status_tags'] = $this->mod_message->calculate_status_tags($item['status']);
		
		$item = $this->mod_message->formatMessageContent($item);
		return $item;
	}
	
	public function parse_template_item($item)
	{
		$mapper_metrix = $this->CI->config->item('mapper_metrix')['message']['template'];
		
		$item['medium_text'] = @$mapper_metrix['medium'][$item['medium']];
		$item['channel_text'] = @$mapper_metrix['channel'][$item['channel']];
		
		return $item;
	}
	
	public function parse_container_item($item)
	{
		if (!function_exists('formatMessageContent')) {
			// TODO maybe todo move it somewhere Right
			function formatMessageContent($formatMessage)
			{
				if(!empty($formatMessage['message_id_content'])) {
					$params = unserialize($formatMessage['message_id_content']);
					extract($params);
				}
				
				$formatMessage['title']      = @eval(sprintf('return "%s";', $formatMessage['template_id_name']));
				$formatMessage['content']    = @eval(sprintf('return "%s";', $formatMessage['template_id_model']));
				
				return $formatMessage;
			}
		}
		$item = formatMessageContent($item);
		$item['status_tags'] = $this->mod_message->calculate_status_tags($item['status'], 'positive', 'container');
		return $item;
	}
	
	/**
	 * 指定ID的消息模板是否已经存在
	 * 
	 * @desc	可能潜在的适用场景：在（?P<场景>后台自由发送消息）时指定模板ID，这个模板是需要存在的！（不过：这种《场景》可能并不存在！）
	 * @date	2017年6月13日 下午5:42:48
	 *
	 * @param number $template_id
	 *
	 * @return boolean
	 */
	public function has_template_exists($template_id)
	{
		$selected_id = $this->mod_message->select_fields_by_id($template_id, ['id'], 'template');
		return !empty($selected_id);
	}
	
	/**
	 * 是否是支持的媒介
	 *
	 * @date	2017年6月13日 下午7:41:03
	 *
	 * @param string $medium
	 *
	 * @return boolean
	 */
	public function is_supported_medium($medium)
	{
		$mapper_metrix = $this->CI->config->item('mapper_metrix')['message']['template'];
		$medium_mapper = $mapper_metrix['medium'];
		
		return array_key_exists($medium, $medium_mapper);
	}
	
	/**
	 * 是否是支持的通道，基于 POST 过来的某种媒介下判断。
	 *
	 * @date	2017年6月13日 下午7:41:03
	 *
	 * @param string $medium
	 *
	 * @return boolean
	 */
	public function is_supported_channel($channel)
	{
		return in_array($channel, [0,1,2,3]);
// 		$post = $this->CI->input->post('medium');
// 		$mapper_metrix = $this->CI->config->item('mapper_metrix')['message']['master'];
// 		$channel_mapper = $mapper_metrix['channel'];
		
// 		return array_key_exists($channel, $channel_mapper);
	}
	
	/**
	 * 消息状态切换（消息发送方的状态是否保留/删除，消息接收方的状态是否保留/删除、是否读取/未读）
	 *
	 * @desc	发送方状态：是否删除，肯定已读取！
	 * @desc	接收方状态：是否删除、是否读取！
	 * @author  Jason
	 * @date	2017年7月24日 下午3:35:42
	 *
	 * @param number $id
	 * @param string $positiveTag eg: 'retained'
	 * @param string $mapping 发送方('master')还是接收方('container')
	 *
	 * @return [<status>, <content>]	一个两元素数组，第一个元素表示状态，第二个表示相应内容
	 * 	        eg:	[true, ['nowTag' => 'enabled']]
	 * 				[true, ['nowTag' => 'disabled']]
	 * 				[false, ['error']]
	 */
	public function toggle_status_positive_tag($mapping = 'master')
	{
		$this->CI->load->library('form_validation');
		
		$status = false;
		$content = [];
		if(FALSE === $this->CI->form_validation->run("toggle_status_positive_tag_for_message")) {
			$errorKey = $this->CI->form_validation->error_array();
			$status = false;
			$content = $errorKey;
		} else {
			$id = $this->CI->input->post('id');
			$positiveTag = $this->CI->input->post('tag');
			
			$status = true;
			$ultimateTag = $this->mod_message->toggle_status_by_tag($id, $positiveTag, $mapping);
			$content = ['nowTag' => $ultimateTag];
		}
		
		return [$status, $content];
	}
	
	public function sendMessagePerform()
	{
		$data = $this->CI->input->post();
		
		// TODO 这里加表单验证
		
		if(isset($data['extra']) && !Utils::isSerialized($data['extra'])) {
			$data['extra'] = Utils::encodeExtra($data['extra']);
		}
		
		if(!empty($data['mobile'])){
			$data['mobile'] = str_replace("\r\n", "\n", $data['mobile']);
			$data['mobile'] = trim($data['mobile'], "\n");
			$data['mobile'] = str_replace("\n", ",", $data['mobile']);
		}
		if(!empty($data['email'])){
			$data['email'] = str_replace("\r\n", "\n", $data['email']);
			$data['email'] = trim($data['email'], "\n");
			$data['email'] = str_replace("\n", ",", $data['email']);
		}
		// 邮件主题
		if(!empty($data['subject'])){
			$data['subject'] = str_replace("\r\n", "\n", $data['subject']);
			$data['subject'] = trim($data['subject'], "\n");
			$data['subject'] = str_replace("\n", ",", $data['subject']);
		}
		if(!empty($data['target_id'])){
			$data['target_id'] = str_replace("\r\n", "\n", $data['target_id']);
			$data['target_id'] = trim($data['target_id'], "\n");
			$data['target_id'] = explode("\n", $data['target_id']);
		}
		if(!empty($data['station_id'])){
			$data['station_id'] = str_replace("\r\n", "\n", $data['station_id']);
			$data['station_id'] = trim($data['station_id'], "\n");
			$data['station_id'] = explode("\n", $data['station_id']);
		}
		// tag_and: 标签AND
		if(!empty($data['feature_id'])){
			$data['feature_id'] = str_replace("\r\n", "\n", $data['feature_id']);
			$data['feature_id'] = trim($data['feature_id'], "\n");
			$data['feature_id'] = explode("\n", $data['feature_id']);
		}
		// registration_id: 注册ID
		if(!empty($data['regist_id'])){
			$data['regist_id'] = str_replace("\r\n", "\n", $data['regist_id']);
			$data['regist_id'] = trim($data['regist_id'], "\n");
			$data['regist_id'] = explode("\n", $data['regist_id']);
		}
		
		if(!empty($data['all'])){
			$data['target_id'] = 0;
		}
		
		$data['source_id'] = $data['source_id'] ?: 0;
		
		list($status, $content) = $this->mod_message->sendMessagePerform($data);
		return [$status, $content];
	}
	
}


class Utils
{


	/**
	 * 编码Extra字段，将数组串行化以便入库
	 *
	 * @param array $extraArray
	 *
	 * @return string
	 */
	public static function encodeExtra($extraArray)
	{
		$extraString = '';
		$extraString = serialize($extraArray);

		return $extraString;
	}

	/**
	 * 解码Extra字段，将库中串行化数据解析成数组供程序用
	 *
	 * @param string $extraString
	 *
	 * @return array
	 */
	public static function decodeExtra($extraString)
	{
		$extraArray = array();
		$extraArray = self::isSerialized($extraString) ? unserialize($extraString) : $extraString;

		return $extraArray;
	}

	/**
	 * 判断一个字符串是否已经串行化
	 *
	 * @param string $str
	 *
	 * @return boolean
	 */
	public static function isSerialized($str) {
		return ($str == serialize(false) || @unserialize($str) !== false);
	}

}